import re

from Tkinter import *

class RegexTester:
	def __init__(self, master):
		# A Frame provides a grid which widgets can be placed onto.  It's similar to
		# Swing's layout managers.
		self.frame = Frame(master)
		self.frame.grid()
		
		# A LabelFrame is a frame which contains widgets which is also labeled.
		self.entry_frame = LabelFrame(self.frame, text="Entry:", padx=10, pady=10)
		# .pack() fits the frame to the size of its contents.
		self.entry_frame.pack(padx=5, pady=5)
		
		Label(self.entry_frame, text="Regexp:").grid(row=0, column=0, sticky=W)
		
		# Entries are simple text boxes.
		self.regex = Entry(self.entry_frame, width=50)
		# .grid() allows us to position widgets inside of a frame.
		self.regex.grid(row=0, column=1)
		
		Label(self.entry_frame, text="Test String:").grid(row=1, column=0, sticky=W)
		
		self.test_string = Entry(self.entry_frame, width=50)
		self.test_string.grid(row=1, column=1)
		
		# Buttons are similar to the above widgets, but also take a "command"
		# parameter.  It specifies the function which is to be executed when the
		# button is clicked.
		self.test = Button(self.entry_frame, text="Test", command=self.test_regex)
		self.test.grid(row=2, column=1, sticky=W)
		
		self.clear = Button(self.entry_frame, text="Clear", command=self.clear)
		self.clear.grid(row=2, column=1, sticky=E)
		
		self.result_frame = LabelFrame(self.frame, text="Results:", padx=10, pady=10)
		self.result_frame.pack(padx=5, pady=5)
		
		# A Text widget is a multi-rowed Entry widget.  It also defaults to a
		# wider size.
		self.results = Text(self.result_frame)
		self.results.grid()
	
	def test_regex(self):
		# .get() retrieves the contents of a widget.  The type returned by .get()
		# depends on the widget.  Entry widgets return str while Scale widgets
		# return int or float.
		regex = self.regex.get()
		test_str = self.test_string.get()
		results = self.results
		
		# I've changed re.finditer to re.findall after tutorial.  This method finds
		# all non-overlapping matches, and is easier to work with.
		matches = re.findall(regex, test_str)
		
		# Give the user visual feedback as to whether or not there were matches.
		if len(matches) == 0:
			self.test_string.config(bg="red")
		else:
			self.test_string.config(bg="green")
		
		# Recall:  INSERT is the cursor position in the Text area.
		results.insert(INSERT, "Testing \"%s\" against \"%s\"\n" % (test_str, regex))
		
		# enumerate() returns a list of tuples from a list.  This allows us to
		# retrieve an item's position in the list.
		for i, match in enumerate(matches):
			results.insert(INSERT, "  match(%d):\n" % i)
			
			# If only one group exists, the match object will be a string.
			#   eg. [(0, "a"), (1, "b"), ...]
			if isinstance(match, str):
				results.insert(INSERT, "    %s\n" % match)
			# Otherwise it will be a tuple which needs to be iterated over again.
			#   eg. [(0, ("a", "b")), ...]
			else:
				for j, result in enumerate(match):
					results.insert(INSERT, "    group(%d):  %s\n" % (j, result))
	
	def clear(self):
		# This string is the row followed by the column.
		self.results.delete("1.0", END)

# Boilerplate, creates a new Tk window and gives it to our class.
root = Tk()
app = RegexTester(root)

root.title("Python GUI RegEx Tester")

# Runs the main GUI event loop which responds to input and updates accordingly.
root.mainloop()
